package com.chaoshan.config;

import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;
import java.util.Arrays;

/**
 * @DATE: 2022/04/28 13:52
 * @Author: 小爽帅到拖网速
 *
 * 职责：1、 configure(ClientDetailsServiceConfigurer clients) 授权客户端信息
 *      2、 configure(AuthorizationServerEndpointsConfigurer endpoints) 配置令牌的对外暴露的访问端点和令牌服务（存取）
 *      3、 configure(AuthorizationServerSecurityConfigurer security) 配置令牌访问端点的安全约束
 */
@Configuration
@EnableAuthorizationServer
// @RequiredArgsConstructor
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {

  @Autowired
  private  PasswordEncoder passwordEncoder;
  @Autowired
  // @Qualifier("clientDetailsService2")
  private ClientDetailsService clientDetailsService;
  @Autowired
  private  TokenStore tokenStore;
  @Autowired
  private  JwtAccessTokenConverter jwtAccessTokenConverter;
  @Autowired
  private  AuthorizationCodeServices authorizationCodeServices;
  @Autowired
  private AuthenticationManager authenticationManager;
/*
  @Autowired
  private UserDetailsService userDetailsService;
*/


  /**
   * 授权客户端信息
   * @param clients
   * @throws Exception
   */
  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    // 数据库方式保存授权客户端信息
    clients.withClientDetails(clientDetailsService);
  }

  /**
   * 令牌访问端点
   * @param endpoints
   * @throws Exception
   */
  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints){
    endpoints
            .authenticationManager(authenticationManager)
            .authorizationCodeServices(authorizationCodeServices)
            .tokenServices(tokenServices())
            // .userDetailsService(userDetailsService)
            .allowedTokenEndpointRequestMethods(HttpMethod.POST);
  }

  /**
   * 配置令牌安全约束
   * @param security
   * @throws Exception
   */
  @Override
  public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
    security
            .tokenKeyAccess("permitAll()")      // oauth/token_key公开访问
            .checkTokenAccess("permitAll()")    // oauth/check_token公开访问
            .allowFormAuthenticationForClients(); //通过表单认证去申请令牌
  }

  @Bean
  public ClientDetailsService clientDetailsService(DataSource dataSource) {
    ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
    ((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(passwordEncoder);
    return clientDetailsService;
  }



  @Bean
  public AuthorizationServerTokenServices tokenServices(){
    DefaultTokenServices service = new DefaultTokenServices();
    service.setClientDetailsService(clientDetailsService);
    service.setSupportRefreshToken(true);  // 支持令牌服务刷新
    service.setTokenStore(tokenStore); // 令牌存储策略
    // 开启令牌增强
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
    service.setTokenEnhancer(tokenEnhancerChain);
    // 设置令牌ttl
    service.setAccessTokenValiditySeconds(172800); // access_token有效期2天
    service.setRefreshTokenValiditySeconds(259200); // refresh_token有效期14天

    return service;
  }

  // 授权码模式，配置授权码服务
  @Bean
  public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
    return new JdbcAuthorizationCodeServices(dataSource);//设置授权码模式的授权码如何存取
  }




}
